#include "qpointfseditordialog.h"
#include "ui_qpointfseditordialog.h"

#include "qcomboitemlistwidget.h"
#include "qpointdialog.h"

#include "../qbaseitemdelegate.h"

#include "../../shared/qcommonstruct.h"

#include <math.h>
#include <QPainter>
#include <QApplication>
#include <QVBoxLayout>
#include <QMouseEvent>

QPointFsEditorDialog::QPointFsEditorDialog(const QVariant &value, enPointType type, QWidget *parent):
    QBaseDialog(parent),
    ui(new Ui::QPointFsEditorDialog),
    m_ret(0),
    m_value(value),
    m_type(type)
{
    ui->setupUi(this);

    ui->point_list->setItemDelegate(new QBaseItemDelegate);
    ui->point_list->setRootIsDecorated(false);
    ui->point_list->setAlternatingRowColors(true);

    QPointFs ps=m_value.value<QPointFs>();
    QString str;

    int width=ui->point_show_widget->width()-20;
    int hei=ui->point_show_widget->height()-20;

    int _x=10;
    int _y=10;

    foreach(QPointF p,ps)
    {
        QTreeWidgetItem *item=new QTreeWidgetItem(ui->point_list);
        str="[ X = "+QString::number((float)p.x())+" , Y = "+QString::number((float)p.y())+" ]";
        QComboItemListWidget *wid=new QComboItemListWidget(item,ui->point_list);
        wid->set_text(str);
        connect(wid,SIGNAL(edit()),this,SLOT(edit()));
        connect(wid,SIGNAL(remove()),this,SLOT(remove()));
        connect(wid,SIGNAL(up()),this,SLOT(up()));
        connect(wid,SIGNAL(down()),this,SLOT(down()));
        ui->point_list->setItemWidget(item,0,wid);

        QWidget* w=new QWidget(ui->point_show_widget);
        w->setCursor(QCursor(Qt::SizeAllCursor));
        w->setFixedSize(9,9);
        w->move(_x+width*p.x()-4,_y+hei*p.y()-4);
        w->installEventFilter(this);
        w->setMouseTracking(true);
        w->setToolTip(str);
        m_point_handle_widgets.append(w);
    }

    ui->point_show_widget->installEventFilter(this);
}

QPointFsEditorDialog::~QPointFsEditorDialog()
{
    delete ui;
}

int QPointFsEditorDialog::get_ret()
{
    return m_ret;
}

QVariant QPointFsEditorDialog::get_value()
{
    return m_value;
}

void QPointFsEditorDialog::on_addBtn_clicked()
{
    QPointDialog dlg(QPointF(1,1),this);

    dlg.exec();

    if(dlg.get_ret()==1)
    {
        int width=ui->point_show_widget->width()-20;
        int hei=ui->point_show_widget->height()-20;

        int _x=10;
        int _y=10;

        QPointF p=dlg.get_point();

        QPointFs fs=m_value.value<QPointFs>();
        fs.append(p);
        m_value.setValue<QPointFs>(fs);

        QTreeWidgetItem *item=new QTreeWidgetItem(ui->point_list);
        QString str="[ X = "+QString::number((float)p.x())+" , Y = "+QString::number((float)p.y())+" ]";
        QComboItemListWidget *wid=new QComboItemListWidget(item,ui->point_list);
        wid->set_text(str);
        connect(wid,SIGNAL(edit()),this,SLOT(edit()));
        connect(wid,SIGNAL(remove()),this,SLOT(remove()));
        connect(wid,SIGNAL(up()),this,SLOT(up()));
        connect(wid,SIGNAL(down()),this,SLOT(down()));
        ui->point_list->setItemWidget(item,0,wid);

        QWidget* w=new QWidget(ui->point_show_widget);
        w->setCursor(QCursor(Qt::SizeAllCursor));
        w->setFixedSize(9,9);
        w->move(_x+width*p.x()-4,_y+hei*p.y()-4);
        w->installEventFilter(this);
        w->setMouseTracking(true);
        w->setToolTip(str);
        w->setVisible(true);
        m_point_handle_widgets.append(w);
    }
}

bool QPointFsEditorDialog::eventFilter(QObject *o, QEvent *e)
{
    if(o==ui->point_show_widget)
    {
        if(e->type()==QEvent::Paint)
        {
            point_draw();
        }
        else if(e->type()==QEvent::MouseButtonPress)
        {
            handle_all_mouse_press((QMouseEvent*)e);
            return true;
        }
        else if(e->type()==QEvent::MouseButtonRelease)
        {
            handle_all_mouse_release((QMouseEvent*)e);
            return true;
        }
        else if(e->type()==QEvent::MouseMove)
        {
            handle_all_mouse_move((QMouseEvent*)e);
            return true;
        }
        return true;
    }
    else if(o->isWidgetType())
    {
        QWidget* wid=(QWidget*)o;
        if(m_point_handle_widgets.contains(wid))
        {
            if(e->type()==QEvent::Paint)
            {
                handle_draw(wid);
                return true;
            }
            else if(e->type()==QEvent::MouseButtonPress)
            {
                handle_mouse_press(wid,(QMouseEvent*)e);
                return true;
            }
            else if(e->type()==QEvent::MouseButtonRelease)
            {
                handle_mouse_release(wid,(QMouseEvent*)e);
                return true;
            }
            else if(e->type()==QEvent::MouseMove)
            {
                handle_mouse_move(wid,(QMouseEvent*)e);
                return true;
            }
            else if(e->type()==QEvent::MouseButtonDblClick)
            {
                handle_mouse_double_press(wid);
                return true;
            }
        }
    }
    return QDialog::eventFilter(o,e);
}

void QPointFsEditorDialog::point_draw()
{
    QPainter p(ui->point_show_widget);
    p.setRenderHint(QPainter::Antialiasing);
    p.fillRect(ui->point_show_widget->rect(),QBrush(QColor(220,220,220)));

    p.setPen(QPen(QBrush(QColor(0,0,0)),2));

    QPointFs ps=m_value.value<QPointFs>();
    QPoint* pt=new QPoint[ps.size()];

    int wid=ui->point_show_widget->width()-20;
    int hei=ui->point_show_widget->height()-20;

    int _x=10;
    int _y=10;

    for(int i=0;i<ps.size();i++)
    {
        QPointF pf=ps.at(i);
        pt[i].setX(_x+(int)(wid*pf.x()));
        pt[i].setY(_y+(int)(hei*pf.y()));
    }
    if(m_type==PT_POLYGON)
    {
        p.drawPolygon(pt,ps.size());
    }
    else if(m_type==PT_LINE)
    {
        p.drawPolyline(pt,ps.size());
    }

    delete [] pt;
}

void QPointFsEditorDialog::handle_draw(QWidget *wid)
{
    QPainter p(wid);
    p.setRenderHint(QPainter::Antialiasing);
    p.setBrush(QBrush(QColor(255,0,0)));
    p.setPen(Qt::transparent);
    p.drawEllipse(wid->rect().adjusted(0,0,-1,-1));
}

void QPointFsEditorDialog::handle_mouse_press(QWidget *wid, QMouseEvent *e)
{
    if(e->button()!=Qt::LeftButton)
    {
        return;
    }

    m_last_point=e->globalPos();
    e->accept();
}

void QPointFsEditorDialog::handle_mouse_move(QWidget *wid, QMouseEvent *e)
{
    if(m_last_point.isNull())
    {
        return;
    }
    QRect re=wid->geometry();

    QPoint pt=re.center()-(m_last_point-e->globalPos());

    int _x=10;
    int _y=10;
    int width=ui->point_show_widget->width()-20;
    int hei=ui->point_show_widget->height()-20;

    if(pt.x()<_x)pt.setX(_x);
    if(pt.y()<_y)pt.setY(_y);
    if(pt.x()>_x+width)pt.setX(_x+width);
    if(pt.y()>_y+hei)pt.setY(_x+hei);

    re.moveCenter(pt);

    m_last_point=e->globalPos();

    if(re!=wid->geometry())
    {
        wid->setGeometry(re);
        QPointFs fs=m_value.value<QPointFs>();
        int index=m_point_handle_widgets.indexOf(wid);
        QPointF pp=fs.at(index);
        pp.setX(((float)(pt.x()-_x))/width);
        pp.setY(((float)(pt.y()-_y))/hei);
        fs.replace(index,pp);
        m_value.setValue<QPointFs>(fs);

        QTreeWidgetItem *item=ui->point_list->topLevelItem(index);
        QComboItemListWidget *item_wid=(QComboItemListWidget*)ui->point_list->itemWidget(item,0);

        QString str="[ X = "+QString::number((float)pp.x())+" , Y = "+QString::number((float)pp.y())+" ]";
        item_wid->set_text(str);
        wid->setToolTip(str);
        ui->point_show_widget->update();
    }
    e->accept();
}

void QPointFsEditorDialog::handle_mouse_release(QWidget *wid, QMouseEvent *e)
{
    m_last_point=QPoint();
    e->accept();
}

void QPointFsEditorDialog::handle_mouse_double_press(QWidget *wid)
{
    edit(m_point_handle_widgets.indexOf(wid));
}

void QPointFsEditorDialog::on_okBtn_clicked()
{
    m_ret=1;
    close();
}

void QPointFsEditorDialog::on_cancelBtn_clicked()
{
    close();
}

void QPointFsEditorDialog::handle_all_mouse_press(QMouseEvent *e)
{
    if(e->button()!=Qt::LeftButton)
    {
        return;
    }

    m_last_point=e->globalPos();
}

void QPointFsEditorDialog::handle_all_mouse_move(QMouseEvent *e)
{
    if(m_last_point.isNull())
    {
        return;
    }

    if(m_last_point==e->globalPos())
    {
        return;
    }

    QPointFs fs=m_value.value<QPointFs>();

    QPoint pt=m_last_point-e->globalPos();

    int width=ui->point_show_widget->width()-20;
    int hei=ui->point_show_widget->height()-20;

    double left,top,right,bottom;
    left=1;
    top=1;
    right=0;
    bottom=0;

    for(int i=0;i<fs.size();i++)
    {
        QPointF p=fs.at(i);
        if(p.x()<left)
        {
            left=p.x();
        }
        if(p.x()>right)
        {
            right=p.x();
        }
        if(p.y()<top)
        {
            top=p.y();
        }
        if(p.y()>bottom)
        {
            bottom=p.y();
        }
    }

    int l,t,r,b;
    l=left*width;
    t=top*hei;
    r=(1-right)*width;
    b=(1-bottom)*hei;

    if(pt.x()<0)
    {
        if(pt.x()<-r)
        {
            pt.setX(-r);
        }
    }
    else if(pt.x()>0)
    {
        if(pt.x()>l)
        {
            pt.setX(l);
        }
    }

    if(pt.y()<0)
    {
        if(pt.y()<-b)
        {
            pt.setY(-b);
        }
    }
    else if(pt.y()>0)
    {
        if(pt.y()>t)
        {
            pt.setY(t);
        }
    }

    for(int i=0;i<fs.size();i++)
    {
        QPointF p=fs.at(i);
        p.setX((p.x()*width-pt.x())/width);
        p.setY((p.y()*hei-pt.y())/hei);
        fs.replace(i,p);
        QWidget* w=m_point_handle_widgets.at(i);
        w->move(10+width*p.x()-4,10+hei*p.y()-4);

        QTreeWidgetItem *item=ui->point_list->topLevelItem(i);
        QComboItemListWidget *item_wid=(QComboItemListWidget*)ui->point_list->itemWidget(item,0);

        QString str="[ X = "+QString::number((float)p.x())+" , Y = "+QString::number((float)p.y())+" ]";
        item_wid->set_text(str);
        w->setToolTip(str);
    }
    m_value.setValue<QPointFs>(fs);
    ui->point_show_widget->update();

    m_last_point=e->globalPos();

}

void QPointFsEditorDialog::handle_all_mouse_release(QMouseEvent *e)
{
    m_last_point=QPoint();
}

void QPointFsEditorDialog::edit()
{
    QWidget *wid=(QWidget*)sender();

    for(int i=0;i<ui->point_list->topLevelItemCount();i++)
    {
        if(ui->point_list->itemWidget(ui->point_list->topLevelItem(i),0)==wid)
        {
            edit(i);
            return;
        }
    }
}

void QPointFsEditorDialog::remove()
{
    QWidget *wid=(QWidget*)sender();

    for(int i=0;i<ui->point_list->topLevelItemCount();i++)
    {
        if(ui->point_list->itemWidget(ui->point_list->topLevelItem(i),0)==wid)
        {
            delete ui->point_list->topLevelItem(i);
            QPointFs fs=m_value.value<QPointFs>();
            fs.removeAt(i);
            delete m_point_handle_widgets.at(i);
            m_value.setValue<QPointFs>(fs);
            ui->point_show_widget->update();
            this->update();
            return;
        }
    }
}

void QPointFsEditorDialog::up()
{
    QWidget *wid=(QWidget*)sender();

    for(int i=0;i<ui->point_list->topLevelItemCount();i++)
    {
        if(ui->point_list->itemWidget(ui->point_list->topLevelItem(i),0)==wid)
        {
            QPointFs fs=m_value.value<QPointFs>();
            m_point_handle_widgets.swap(i,i-1);
            QPointF p=fs.at(i);
            fs.swap(i,i-1);
            QTreeWidgetItem *item=ui->point_list->takeTopLevelItem(i);
            ui->point_list->insertTopLevelItem(i-1,item);

            QString str="[ X = "+QString::number((float)p.x())+" , Y = "+QString::number((float)p.y())+" ]";
            QComboItemListWidget *w=new QComboItemListWidget(item,ui->point_list);
            w->set_text(str);
            connect(w,SIGNAL(edit()),this,SLOT(edit()));
            connect(w,SIGNAL(remove()),this,SLOT(remove()));
            connect(w,SIGNAL(up()),this,SLOT(up()));
            connect(w,SIGNAL(down()),this,SLOT(down()));
            ui->point_list->setItemWidget(item,0,w);

            m_value.setValue<QPointFs>(fs);
            this->update();
            return;
        }
    }
}

void QPointFsEditorDialog::down()
{
    QWidget *wid=(QWidget*)sender();

    for(int i=0;i<ui->point_list->topLevelItemCount();i++)
    {
        if(ui->point_list->itemWidget(ui->point_list->topLevelItem(i),0)==wid)
        {
            QPointFs fs=m_value.value<QPointFs>();
            m_point_handle_widgets.swap(i,i+1);
            QPointF p=fs.at(i);
            fs.swap(i,i+1);
            QTreeWidgetItem *item=ui->point_list->takeTopLevelItem(i);
            ui->point_list->insertTopLevelItem(i+1,item);

            QString str="[ X = "+QString::number((float)p.x())+" , Y = "+QString::number((float)p.y())+" ]";
            QComboItemListWidget *w=new QComboItemListWidget(item,ui->point_list);
            w->set_text(str);
            connect(w,SIGNAL(edit()),this,SLOT(edit()));
            connect(w,SIGNAL(remove()),this,SLOT(remove()));
            connect(w,SIGNAL(up()),this,SLOT(up()));
            connect(w,SIGNAL(down()),this,SLOT(down()));
            ui->point_list->setItemWidget(item,0,w);

            m_value.setValue<QPointFs>(fs);
            this->update();
            return;
        }
    }
}

void QPointFsEditorDialog::edit(int index)
{
    QPointFs fs=m_value.value<QPointFs>();

    QPointF f=fs.at(index);

    QPointDialog dlg(f,this);
    dlg.exec();
    int width=ui->point_show_widget->width()-20;
    int hei=ui->point_show_widget->height()-20;
    if(dlg.get_ret()==1)
    {
        if(dlg.get_point()!=f)
        {
            f=dlg.get_point();
            fs.replace(index,f);

            QWidget* w=m_point_handle_widgets.at(index);
            w->move(10+width*f.x()-4,10+hei*f.y()-4);

            QTreeWidgetItem *item=ui->point_list->topLevelItem(index);
            QComboItemListWidget *item_wid=(QComboItemListWidget*)ui->point_list->itemWidget(item,0);

            QString str="[ X = "+QString::number((float)f.x())+" , Y = "+QString::number((float)f.y())+" ]";
            item_wid->set_text(str);
            w->setToolTip(str);

            m_value.setValue<QPointFs>(fs);
            this->update();
        }
    }
}

void QPointFsEditorDialog::on_autoBtn_clicked()
{
    QPointFs fs=m_value.value<QPointFs>();

    int count=fs.size();
    if(m_type==PT_LINE)
    {
        count--;
    }

    if(count<3)
    {
        return;
    }


    for(int i=0;i<count;i++)
    {
        QPointF f=fs.at(i);
        f.setX(0.5+cos(2*M_PI*i/count)*0.5);
        f.setY(0.5-sin(2*M_PI*i/count)*0.5);
        fs.replace(i,f);
    }

    if(m_type==PT_LINE)
    {
        QPointF f=fs.at(count);
        f=fs.first();
        fs.replace(count,f);
    }

    int width=ui->point_show_widget->width()-20;
    int hei=ui->point_show_widget->height()-20;
    for(int i=0;i<fs.size();i++)
    {
        QPointF p=fs.at(i);
        QWidget* w=m_point_handle_widgets.at(i);
        w->move(10+width*p.x()-4,10+hei*p.y()-4);

        QTreeWidgetItem *item=ui->point_list->topLevelItem(i);
        QComboItemListWidget *item_wid=(QComboItemListWidget*)ui->point_list->itemWidget(item,0);

        QString str="[ X = "+QString::number((float)p.x())+" , Y = "+QString::number((float)p.y())+" ]";
        item_wid->set_text(str);
        w->setToolTip(str);
    }
    m_value.setValue<QPointFs>(fs);
    ui->point_show_widget->update();
}
